package com.atguigu.yuntai.schedule.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.yuntai.schedule.entity.TDsTaskDefinition;
import com.atguigu.yuntai.schedule.mapper.TDsProcessDefinitionMapper;
import com.atguigu.yuntai.schedule.mapper.TDsTaskDefinitionMapper;
import com.atguigu.yuntai.schedule.service.TDsProcessDefinitionService;
import com.atguigu.yuntai.schedule.service.TDsTaskDefinitionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 任务定义实现类
 */
@Service
public class TDsTaskDefinitionServiceImpl extends ServiceImpl<TDsTaskDefinitionMapper, TDsTaskDefinition> implements TDsTaskDefinitionService {

    @Autowired
    TDsTaskDefinitionMapper tDsTaskDefinitionMapper;

    @Autowired
    TDsProcessDefinitionService  tDsProcessDefinitionService;



    @Override
    public List<String> getAllTaskSql(){

        List<Long> releastCodeList = tDsProcessDefinitionService.getReleastCodeList();

        List<String> taskSqlList = parseSqlFromTaskSQL(releastCodeList);
        List<String> taskSqlFromShellList =parseSqlFromTaskSHELL( releastCodeList);
        taskSqlList.addAll(taskSqlFromShellList);

        return taskSqlList;

    }

    @Override
    public  String  getTaskSqlByName(String tableName){
        List<Long> releastCodeList = tDsProcessDefinitionService.getReleastCodeList();
        String  taskSql  = parseSqlFromTaskSQLByName(releastCodeList,tableName);
        if(taskSql==null){
            taskSql= parseSqlFromTaskSHELLByName(releastCodeList,tableName);
        }
        return taskSql;

    }




    @Override
    public TDsTaskDefinition getReleastTaskDefinitionByName(String tableName){
        List<Long> releastCodeList = tDsProcessDefinitionService.getReleastCodeList();
        TDsTaskDefinition taskDefinition = tDsTaskDefinitionMapper.getTaskDefinitionByName(releastCodeList,tableName);
        return taskDefinition;

    }


    private List<String> parseSqlFromTaskSQL(List<Long> codeList){
        List<String> taskSqlList=new ArrayList<>();
        List<String> taskjsonList= tDsTaskDefinitionMapper.getTaskDefinitionSQL(codeList);
        for (String taskJson : taskjsonList) {
            taskSqlList.addAll(getSqlFromTaskJson(taskJson));
        }
        return taskSqlList;
    }

    private   String   parseSqlFromTaskSQLByName(List<Long> codeList ,String tableName){
        String   taskjson = tDsTaskDefinitionMapper.getTaskDefinitionSQLByName(codeList,tableName);
        if(taskjson!=null&&taskjson.length()>0){
            List<String> sqlFromTaskJsonList = getSqlFromTaskJson(taskjson);
            if(sqlFromTaskJsonList.size()>0){
                return  sqlFromTaskJsonList.get(0);
            }else {
                return null;
            }
        }
        return null;

    }


    private List<String>  getSqlFromTaskJson(String taskJson){
        JSONObject taskJsonObj = JSON.parseObject(taskJson);
        String taskSql = taskJsonObj.getString("sql");
        String[] sqlArr = taskSql.split(";");
        List<String> taskSqlList=new ArrayList<>();
        for (String sql : sqlArr) {
            sql = sql.replace("\n", " ");

            sql = sql.replace("\\`", "`");
            if(sql.trim().startsWith("set")) {
                continue;
            }
            sql = sql.replaceAll("\\$\\{\\w+\\}", "9999");
            taskSqlList.add(sql);
        }
        return taskSqlList;
    }

    //总程序 从shell脚本提取sql清单
    private static    List<String>  getSqlListFromShell (String shellScript){
        int sqlStartIdx = shellScript.indexOf("insert");
        if(sqlStartIdx<0){
            return  new ArrayList<>();
        }

        Map<String, String> paramMap = extractParams(shellScript.substring(0, sqlStartIdx));

        String sqlShell=shellScript.substring(sqlStartIdx);
        List<String> sqlList = getSqlListFromSqlShell(sqlShell, paramMap);

        return sqlList;
    }



    //   从shell脚本提取sql清单
    private  static List<String>  getSqlListFromSqlShell(String shellScript,Map<String,String>  paramMap){
        List<String> taskSqlList=new ArrayList<>();
        int fromIdx=0;
        while(true){
            String shellScriptNoWrap = shellScript.replace("\\n", " ");
            int sqlStartIdx = shellScriptNoWrap.indexOf("insert",fromIdx);
            if(sqlStartIdx<0){  //至到无法检查出insert 退出提取
                break;
            }
            int sqlEndIdx = shellScriptNoWrap.indexOf(";", sqlStartIdx);
            if(sqlEndIdx<0){
                sqlEndIdx=shellScriptNoWrap.length();
            }
            String sql = shellScriptNoWrap.substring(sqlStartIdx, sqlEndIdx);

            String sqlWithParam = replaceParam(sql, paramMap);
            String sqlWithoutValue=replaceValue(sqlWithParam);
            taskSqlList.add(sqlWithoutValue);

            fromIdx=sqlEndIdx;
        }
        return taskSqlList;
    }


    private static  String replaceValue(String sql  ) {
        sql = sql.replaceAll("\'.+?\'", "'0'");
        sql = sql.replace("\\`", "`");

        return  sql;
    }




    //   把sql中的参数替换
    private static  String replaceParam(String sql ,Map<String,String>  paramMap){

        for (Map.Entry<String, String> param : paramMap.entrySet()) {
            String key = param.getKey();
            String value = param.getValue();
            sql = sql.replaceAll("(\\$\\{" + key + "\\}|\\$" + key + ")", value);

        }

        // sql.replace("")



        return  sql;
    }
    //   从shell脚本提取参数映射
    private static Map<String,String>  extractParams(String shellScript){
        Pattern p = Pattern.compile("(\\w+)(=)(.+){1}");//正则表达式，取=和|之间的字符串，不包括=和|

        Map<String, String> paramMap = new HashMap<>();

        String[] shell = StringUtils.split(shellScript, "\n");
        // String[] shell = shellScript.split("\\\n");
        for (String shellLine : shell) {
            shellLine= shellLine.trim();
            boolean isMatchParamPattern = p.matcher(shellLine).matches();
            if(isMatchParamPattern){
                String[] paramPattern = shellLine.trim().split("=");
                String param = paramPattern[0];
                String value = paramPattern[1];
                if( value.contains("$")){
                    value="9999";
                }

                paramMap.put(param,value);
            }

        }
        return  paramMap;

    }





    private List<String> parseSqlFromTaskSHELL(List<Long> codeList){
        List<String> taskSqlList=new ArrayList<>();
        List<String> taskjsonList= tDsTaskDefinitionMapper.getTaskDefinitionSHELL(codeList);
        for (String taskJson : taskjsonList) {
            JSONObject taskJsonObj = JSON.parseObject(taskJson);
            String shellScript = taskJsonObj.getString("rawScript");
            List<String> sqlList = getSqlListFromShell(shellScript);
            taskSqlList.addAll(sqlList);

        }
        return taskSqlList;
    }

    private  String  parseSqlFromTaskSHELLByName(List<Long> codeList,String tableName){
        List<String> taskSqlList=new ArrayList<>();
        String taskjson = tDsTaskDefinitionMapper.getTaskDefinitionSHELLByName(codeList,tableName);
        if(taskjson==null||taskjson.length()==0){
            return null;
        }
        JSONObject taskJsonObj = JSON.parseObject(taskjson);
        String shellScript = taskJsonObj.getString("rawScript");
        List<String> sqlList = getSqlListFromShell(shellScript);
        taskSqlList.addAll(sqlList);
        if(taskSqlList.size()>0){
            return taskSqlList.get(0);
        }else{
            return null;
        }


    }



    private static boolean  checkValidTable(String tableName){
        if(tableName.indexOf(".")>=0){ //不含库名的认定为临时表
            return  false;
        }
        return true;
    }


}
